#ifndef __PTHREADINTERFACE_H__
#define __PTHREADINTERFACE_H__

#include <pthread.h>

#include "util/Pool.h"
#include "base/threads/SimulatedState.h"

class PthreadKeys;
// PthreadInterface must be instantiated very early in the load
// process so we don't use pooling.
class PthreadInterface {
  public:
    static PthreadInterface* getPthreadInterface () {
        return _pthreadInterface;
    }
    static void setPthreadInterface (PthreadInterface* pi);
    static PthreadInterface* reset ();
    
    static SimulatedState simState;
    PthreadInterface ();
    virtual ~PthreadInterface () {};
    void init ();
    void fini ();
    void captureSimulatedState();
    virtual int create (pthread_t* thread,
                        const pthread_attr_t* attr,
                        void *(*start_routine)(void*), 
                        void* arg);
    pthread_t self ();
    int join (pthread_t thread, void** status);

    virtual void exit (void* status);
    virtual int mutex_lock (pthread_mutex_t* lock);
    virtual int mutex_unlock (pthread_mutex_t* lock);
    virtual int mutex_trylock (pthread_mutex_t* lock);

    int rwlock_init (pthread_rwlock_t* lock, const pthread_rwlockattr_t* attr);
    int rwlock_destroy (pthread_rwlock_t* lock);
    virtual int rwlock_rdlock (volatile pthread_rwlock_t* lock);
    virtual int rwlock_wrlock (volatile pthread_rwlock_t* lock);
    virtual int rwlock_unlock (pthread_rwlock_t* lock);

    virtual int key_create (pthread_key_t* key, void (*destructor)(void*));
    int setspecific (pthread_key_t key, const void* value);
    void* getspecific (pthread_key_t key);

    int cond_init (pthread_cond_t* cond, const pthread_condattr_t* attr);
    int cond_destroy (pthread_cond_t* cond);
    int cond_broadcast (pthread_cond_t* cond);
    int cond_signal (pthread_cond_t* cond);
    virtual int cond_wait (pthread_cond_t* cond, pthread_mutex_t* lock);

    int barrier_init (pthread_barrier_t* barrier,
                              const pthread_barrierattr_t* attr, unsigned count);
    int barrier_destroy (pthread_barrier_t* barrier);
    virtual int barrier_wait (pthread_barrier_t* barrier);

    int kill (pthread_t thread, int sig);

    int equal (pthread_t t1, pthread_t t2);
  protected:
    // key data/lock is protected, not private, so children can overwrite
    // key function implementation
    PthreadKeys *pthreadkeys; // is shared by children classes
    volatile int key_lock;


  private:
    static PthreadInterface* _pthreadInterface;
    static PthreadInterface pthreadInterfaceReal;
    
    /** 
        This selfPtr is necessary to make the initialization of
        PthreadInterface::pthreadInterface work on newer Linuxes such
        as Fedora Core 6.
    */
    virtual PthreadInterface* selfPtr () { return this; }

};

typedef struct {
    volatile int value;
    long _padding[15]; /* to prevent false sharing */
} tree_barrier_t;

// old LinuxThreads needs different magic than newer NPTL implementation
// definitions for LinuxThreads
#ifdef __linux__
#ifndef  __SIZEOF_PTHREAD_MUTEX_T
#define PTHREAD_MUTEX_T_COUNT __m_count
struct _pthread_descr_struct 
{
    int cond_t_flag;
    int cond_t_thread_count;
    int cond_t_count_lock;
    
    int rwlock_t_lock;
    int rwlock_t_readers;
    int rwlock_t_writer;
};
#define PTHREAD_COND_T_INIT(cond) if (cond->__c_waiting == NULL) cond->__c_waiting = (struct _pthread_descr_struct*)malloc(sizeof(struct _pthread_descr_struct));
#define PTHREAD_COND_T_DESTROY(cond) if (cond->__c_waiting) free(cond->__c_waiting);
#define PTHREAD_COND_T_FLAG __c_waiting->cond_t_flag
#define PTHREAD_COND_T_THREAD_COUNT __c_waiting->cond_t_thread_count
#define PTHREAD_COND_T_COUNT_LOCK __c_waiting->cond_t_count_lock
#define PTHREAD_RWLOCK_T_INIT(lock) if (lock->__rw_writer == NULL) lock->__rw_writer = (struct _pthread_descr_struct*)malloc(sizeof(struct _pthread_descr_struct));
#define PTHREAD_RWLOCK_T_DESTROY(lock) if (lock->__rw_writer) free(lock->__rw_writer);
#define PTHREAD_RWLOCK_T_LOCK __rw_writer->rwlock_t_lock
#define PTHREAD_RWLOCK_T_READERS __rw_writer->rwlock_t_readers
#define PTHREAD_RWLOCK_T_WRITER __rw_writer->rwlock_t_writer
#define PTHREAD_BARRIER_T_NUM_THREADS(barrier)  (*(int32*)(&barrier->__ba_lock.__spinlock))
#define PTHREAD_BARRIER_T_BARRIER_PTR(barrier) (*(tree_barrier_t**)(&barrier->__ba_required))
// definitions for NPTL implementation
#else /* __SIZEOF_PTHREAD_MUTEX_T defined */
#define PTHREAD_MUTEX_T_COUNT __data.__count
#define PTHREAD_RWLOCK_T_INIT(lock)
#define PTHREAD_RWLOCK_T_DESTROY(lock)
#define PTHREAD_RWLOCK_T_LOCK __data.__lock
#define PTHREAD_RWLOCK_T_READERS __data.__nr_readers
#define PTHREAD_RWLOCK_T_WRITER __data.__writer
#if defined(__GNUC__) && __GNUC__ >= 4
#define PTHREAD_COND_T_INIT(cond)
#define PTHREAD_COND_T_DESTROY(cond)
#define PTHREAD_COND_T_FLAG __data.__lock
#define PTHREAD_COND_T_THREAD_COUNT __data.__futex
#define PTHREAD_COND_T_COUNT_LOCK __data.__nwaiters
#define PTHREAD_BARRIER_T_NUM_THREADS(barrier)  (*((int32*)(barrier->__size+(0*sizeof(int32)))))
#define PTHREAD_BARRIER_T_BARRIER_PTR(barrier) (*(tree_barrier_t**)(barrier->__size+(1*sizeof(int32))))
#ifndef __SIZEOF_PTHREAD_BARRIER_T
#error __SIZEOF_PTHREAD_BARRIER_T not defined
#endif
#if ((4/*fields*/*4/*sizeof(int32)*/) > __SIZEOF_PTHREAD_BARRIER_T)
#error barrier size __SIZEOF_PTHREAD_BARRIER_T not large enough for our implementation
#endif
#else // gnuc >= 4
#define PTHREAD_COND_T_INIT(cond)
#define PTHREAD_COND_T_DESTROY(cond)
#define PTHREAD_COND_T_FLAG __data.__lock
#define PTHREAD_COND_T_THREAD_COUNT __data.__clock
#define PTHREAD_COND_T_COUNT_LOCK __data.__total_seq
#endif // gnuc >= 4
#endif // LinuxThreads

// non-linux definitions... fill this in?
#else // !__linux__
#define PTHREAD_RWLOCK_T_LOCK sig 
#define PTHREAD_RWLOCK_T_READERS opaque[0] 
#define PTHREAD_RWLOCK_T_WRITER opaque[4] 
#endif //!__linux__

#endif //  __PTHREADINTERFACE_H__
